﻿using System;
using Microsoft.Xna.Framework;
using Phoenix.Xna.Framework;
using Phoenix.Xna.Framework.Components;
using Phoenix.Xna.Framework.Components.Cameras;
using Phoenix.Xna.Framework.Components.Terrain;
using Phoenix.Xna.Framework.FrameworkExtensions;
using Phoenix.Xna.Framework.Graphics.Animation;
using Phoenix.Xna.Framework.Graphics.Models;
using Phoenix.Xna.Framework.Input;
using Phoenix.Xna.Framework.Input.Mice;
using Phoenix.Xna.Framework.Input.Keyboards;

namespace EngineTest.Components.Units
{
    public class Marine : DrawableComponent, I3DComponent
    {
        private SkinnedModel _model;
        private bool _leftMouseButtonDown;
        private bool _running;
        private float _cameraPitch;

        public ICamera Camera { get; set; }
        public Vector3 CameraOffset { get; set; }
        public ProgressiveTerrain Terrain { get; set; }
        public float RotationDelta { get; set; }
        public float MoveDelta { get; set; }

        public Marine()
            : base()
        {
            _model = Engine.Instance.Content.Load<SkinnedModel>(@"Models\PlayerMarine");
            CameraOffset = new Vector3(0, 30, -40);
        }

        public Marine(string id)
            : base(id)
        {
            _model = Engine.Instance.Content.Load<SkinnedModel>(@"Models\PlayerMarine");
            CameraOffset = new Vector3(0, 30, -40);
        }

        public void Idle()
        {
            _model.CrossFade("Idle", TimeSpan.FromSeconds(0.3f));
        }

        public void Run(bool forward)
        {
            _running = true;
            _model.AnimationController.Speed = 2;

            if (forward)
            {
                _model.AnimationController.PlaybackMode = PlaybackMode.Forward;
            }
            else
            {
                _model.AnimationController.PlaybackMode = PlaybackMode.Backward;
            }

            _model.CrossFade("Run", TimeSpan.FromSeconds(0.3f));
        }

        private void UpdatePosition(float delta, Vector3 rotation)
        {
            Position += delta * Vector3.Transform(rotation, Rotation);
        }

        protected virtual void OnAxisChanged(object sender, InputMapEventArgs<MouseAxisMap> e)
        {
            if (_leftMouseButtonDown)
            {
                EulerRotation = new Vector3(EulerRotation.X - (RotationDelta * e.InputMap.CurrentPositionDelta.X), 0, 0);
                Camera.SetEulerRotation(null, Camera.EulerRotation.Y - (RotationDelta * e.InputMap.CurrentPositionDelta.Y), null);
            }
        }

        protected virtual void OnMoveLeft(object sender, InputMapEventArgs<KeyboardKeyMap> e)
        {
            EulerRotation = new Vector3(EulerRotation.X - RotationDelta, 0, 0);
        }

        protected virtual void OnMoveRight(object sender, InputMapEventArgs<KeyboardKeyMap> e)
        {
            EulerRotation = new Vector3(EulerRotation.X + RotationDelta, 0, 0);
        }

        protected virtual void OnMoveForward(object sender, InputMapEventArgs<KeyboardKeyMap> e)
        {
            if (!_running)
            {
                Run(true);
            }

            UpdatePosition(MoveDelta, -Vector3.Forward);
        }

        protected virtual void OnMoveBackward(object sender, InputMapEventArgs<KeyboardKeyMap> e)
        {
            if (!_running)
            {
                Run(false);
            }

            UpdatePosition(MoveDelta, Vector3.Forward);
        }

        protected virtual void OnStopRun(object sender, InputMapEventArgs<KeyboardKeyMap> e)
        {
            _model.AnimationController.Speed = 1;
            _running = false;
            Idle();
        }

        private void OnLeftMouseButtonPressed(object sender, InputMapEventArgs<MouseButtonMap> e)
        {
            _leftMouseButtonDown = true;
        }

        private void OnLeftMouseButtonReleased(object sender, InputMapEventArgs<MouseButtonMap> e)
        {
            _leftMouseButtonDown = false;
        }

        #region IComponentMembers

        public override void Initialize()
        {
            RotationDelta = 0.005f;
            MoveDelta = 10f;
            _model.Initialize();
            _model.StartClip("Idle");
            base.Initialize();
        }

        public override void Update(GameTime gameTime)
        {
            if (Enabled)
            {
                if (Terrain != null)
                {
                    _model.SetPosition(null, Terrain.GetHeight(Position.X, Position.Z) + 1, null);
                }

                _model.Update(gameTime);
                base.Update(gameTime);

                if (Camera != null)
                {
                    Matrix rotationMatrix = Matrix.CreateRotationY(EulerRotation.X);
                    Vector3 transformedReference = Vector3.Transform(CameraOffset, rotationMatrix);
                    Vector3 cameraPosition = transformedReference + Position;
                    Camera.Position = cameraPosition;
                    
                    //Camera.LookAt(Position + new Vector3(0, 10, 0));
                    Matrix rotation = Matrix.CreateWorld(Position, Position - Camera.Position, Vector3.Up);
                    Vector3 euler = rotation.ToEulerAngle();
                    Camera.SetEulerRotation(euler.X, null, null);
                }
            }
        }

        #endregion

        #region IDrawableComponent Members

        public override void UnloadContent()
        {
            _model.Dispose();
            base.UnloadContent();
        }

        public override void Draw(GameTime gameTime)
        {
            if (Visible)
            {
                _model.Draw(gameTime);
                base.Draw(gameTime);
            }
        }

        #endregion

        #region I3DComponent Members

        public Vector3 Forward
        {
            get { return _model.Forward; }
        }
        public Vector3 Up
        {
            get { return _model.Up; }
        }
        public Vector3 Right
        {
            get { return _model.Right; }
        }
        public Vector3 Position
        {
            get { return _model.Position; }
            set { _model.Position = value; }
        }
        public Vector2 Scale
        {
            get { return _model.Scale; }
            set { _model.Scale = value; }
        }
        public Vector3 EulerRotation
        {
            get { return _model.EulerRotation; }
            set { _model.EulerRotation = value; }
        }
        public Matrix Rotation
        {
            get { return _model.Rotation; }
        }
        public BoundingBox BoundingBox
        {
            get { return _model.BoundingBox; }
        }

        public void SetPosition(float? x, float? y, float? z)
        {
            _model.SetPosition(x, y, z);
        }

        public void SetEulerRotation(float? yaw, float? pitch, float? roll)
        {
            _model.SetEulerRotation(yaw, pitch, roll);
        }

        #endregion
    }
}
